{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tce3stUlHN0L"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "tuOe1ymfHZPu"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qFdPvlXBOdUN"
      },
      "source": [
        "# 텐서 소개"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MfBg1C5NB3X0"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/guide/tensor\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/guide/tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행하기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/guide/tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/guide/tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드하기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AL2hzxorJiWy"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import numpy as np"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VQ3s2J8Vgowq"
      },
      "source": [
        "텐서는 일관된 유형(`dtype`이라고 불림)을 가진 다차원 배열입니다. 지원되는 모든 `dtypes`은 `tf.dtypes.DType`에서 볼 수 있습니다.\n",
        "\n",
        "[NumPy](https://numpy.org/devdocs/user/quickstart.html)에 익숙하다면, 텐서는 일종의 `np.arrays`와 같습니다.\n",
        "\n",
        "모든 텐서는 Python 숫자 및 문자열과 같이 변경할 수 없습니다. 텐서의 내용을 업데이트할 수 없으며 새로운 텐서를 만들 수만 있습니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DRK5-9EpYbzG"
      },
      "source": [
        "## 기초\n",
        "\n",
        "기본 텐서를 만들어 봅시다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uSHRFT6LJbxq"
      },
      "source": [
        "다음은 \"스칼라\" 또는 \"순위-0\" 텐서입니다. 스칼라는 단일 값을 포함하며 \"축\"은 없습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d5JcgLFR6gHv"
      },
      "outputs": [],
      "source": [
        "# This will be an int32 tensor by default; see \"dtypes\" below.\n",
        "rank_0_tensor = tf.constant(4)\n",
        "print(rank_0_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tdmPAn9fWYs5"
      },
      "source": [
        "\"벡터\" 또는 \"순위-1\" 텐서는 값의 목록과 같습니다. 벡터는 1축입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oZos8o_R6oE7"
      },
      "outputs": [],
      "source": [
        "# Let's make this a float tensor.\n",
        "rank_1_tensor = tf.constant([2.0, 3.0, 4.0])\n",
        "print(rank_1_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G3IJG-ug_H4u"
      },
      "source": [
        "\"행렬\" 또는 \"rank-2\" 텐서에는 2축이 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cnOIA_xb6u0M"
      },
      "outputs": [],
      "source": [
        "# If we want to be specific, we can set the dtype (see below) at creation time\n",
        "rank_2_tensor = tf.constant([[1, 2],\n",
        "                             [3, 4],\n",
        "                             [5, 6]], dtype=tf.float16)\n",
        "print(rank_2_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "19m72qEPkfxi"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>스칼라, 형상: <code>[]</code>\n",
        "</th>\n",
        "  <th>벡터, 형상: <code>[3]</code>\n",
        "</th>\n",
        "  <th>행렬, 형상: <code>[3, 2]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td><img alt=\"A scalar, the number 4\" src=\"images/tensor/scalar.png\"></td>\n",
        "  <td><img alt=\"The line with 3 sections, each one containing a number.\" src=\"images/tensor/vector.png\"></td>\n",
        "  <td><img alt=\"A 3x2 grid, with each cell containing a number.\" src=\"images/tensor/matrix.png\"></td>\n",
        "</tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fjFvzcn4_ehD"
      },
      "source": [
        "텐서에는 더 많은 축이 있을 수 있습니다. 여기에는 3축 텐서가 사용됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sesW7gw6JkXy"
      },
      "outputs": [],
      "source": [
        "# There can be an arbitrary number of\n",
        "# axes (sometimes called \"dimensions\")\n",
        "rank_3_tensor = tf.constant([\n",
        "  [[0, 1, 2, 3, 4],\n",
        "   [5, 6, 7, 8, 9]],\n",
        "  [[10, 11, 12, 13, 14],\n",
        "   [15, 16, 17, 18, 19]],\n",
        "  [[20, 21, 22, 23, 24],\n",
        "   [25, 26, 27, 28, 29]],])\n",
        "                    \n",
        "print(rank_3_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rM2sTGIkoE3S"
      },
      "source": [
        "2축 이상의 텐서를 시각화하는 방법에는 여러 가지가 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NFiYfNMMhDgL"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th colspan=\"3\">3축 텐서, 형상: <code>[3, 2, 5]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td><img src=\"images/tensor/3-axis_numpy.png\"></td>\n",
        "  <td><img src=\"images/tensor/3-axis_front.png\"></td>\n",
        "  <td><img src=\"images/tensor/3-axis_block.png\"></td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oWAc0U8OZwNb"
      },
      "source": [
        "`np.array` 또는 `tensor.numpy` 메서드를 사용하여 텐서를 NumPy 배열로 변환할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "J5u6_6ZYaS7B"
      },
      "outputs": [],
      "source": [
        "np.array(rank_2_tensor)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "c6Taz2gIaZeo"
      },
      "outputs": [],
      "source": [
        "rank_2_tensor.numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hnz19F0ocEKD"
      },
      "source": [
        "텐서에는 종종 float와 int가 포함되지만, 다음과 같은 다른 유형도 있습니다.\n",
        "\n",
        "- 복소수\n",
        "- 문자열\n",
        "\n",
        "기본 `tf.Tensor` 클래스에서는 텐서가 \"직사각형\"이어야 합니다. 즉, 각 축을 따라 모든 요소의 크기가 같습니다. 그러나 다양한 형상을 처리할 수 있는 특수 유형의 텐서가 있습니다.\n",
        "\n",
        "- 비정형(아래의 [RaggedTensor](#ragged_tensors) 참조)\n",
        "- 희소(아래의 [SparseTensor](#sparse_tensors) 참조)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SDC7OGeAIJr8"
      },
      "source": [
        "덧셈, 요소별 곱셈 및 행렬 곱셈을 포함하여 텐서에 대한 기본 수학을 수행 할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-DTkjwDOIIDa"
      },
      "outputs": [],
      "source": [
        "a = tf.constant([[1, 2],\n",
        "                 [3, 4]])\n",
        "b = tf.constant([[1, 1],\n",
        "                 [1, 1]]) # Could have also said `tf.ones([2,2])`\n",
        "\n",
        "print(tf.add(a, b), \"\\n\")\n",
        "print(tf.multiply(a, b), \"\\n\")\n",
        "print(tf.matmul(a, b), \"\\n\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2smoWeUz-N2q"
      },
      "outputs": [],
      "source": [
        "print(a + b, \"\\n\") # element-wise addition\n",
        "print(a * b, \"\\n\") # element-wise multiplication\n",
        "print(a @ b, \"\\n\") # matrix multiplication"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "S3_vIAl2JPVc"
      },
      "source": [
        "텐서는 모든 종류의 연산(ops)에 사용됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Gp4WUYzGIbnv"
      },
      "outputs": [],
      "source": [
        "c = tf.constant([[4.0, 5.0], [10.0, 1.0]])\n",
        "\n",
        "# Find the largest value\n",
        "print(tf.reduce_max(c))\n",
        "# Find the index of the largest value\n",
        "print(tf.argmax(c))\n",
        "# Compute the softmax\n",
        "print(tf.nn.softmax(c))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NvSAbowVVuRr"
      },
      "source": [
        "## 형상 정보"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hkaBIqkTCcGY"
      },
      "source": [
        "텐서는 형상이 있습니다. 사용되는 일부 용어는 다음과 같습니다.\n",
        "\n",
        "- **형상**: 텐서의 각 차원의 길이(요소의 수)\n",
        "- **순위**: 텐서 차원의 수입니다. 스칼라는 순위가 0이고 벡터의 순위는 1이며 행렬의 순위는 2입니다.\n",
        "- **축** 또는 **차원**: 텐서의 특정 차원\n",
        "- **크기**: 텐서의 총 항목 수, 곱 형상 벡터\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "E9L3-kCQq2f6"
      },
      "source": [
        "참고: \"2차원 텐서\"에 대한 참조가 있을 수 있지만, 순위-2 텐서는 일반적으로 2D 공간을 설명하지 않습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VFOyG2tn8LhW"
      },
      "source": [
        "텐서 및 `tf.TensorShape` 객체에는 다음에 액세스하기 위한 편리한 속성이 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RyD3yewUKdnK"
      },
      "outputs": [],
      "source": [
        "rank_4_tensor = tf.zeros([3, 2, 4, 5])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oTZZW9ziq4og"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th colspan=\"2\">순위-4 텐서, 형상: <code>[3, 2, 4, 5]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td> <img alt=\"A tensor shape is like a vector.\" src=\"images/tensor/shape.png\">\n",
        "</td>\n",
        "<td> <img alt=\"A 4-axis tensor\" src=\"images/tensor/4-axis_block.png\">\n",
        "</td>\n",
        "  </tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MHm9vSqogsBk"
      },
      "outputs": [],
      "source": [
        "print(\"Type of every element:\", rank_4_tensor.dtype)\n",
        "print(\"Number of dimensions:\", rank_4_tensor.ndim)\n",
        "print(\"Shape of tensor:\", rank_4_tensor.shape)\n",
        "print(\"Elements along axis 0 of tensor:\", rank_4_tensor.shape[0])\n",
        "print(\"Elements along the last axis of tensor:\", rank_4_tensor.shape[-1])\n",
        "print(\"Total number of elements (3*2*4*5): \", tf.size(rank_4_tensor).numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bQmE_Vx5JilS"
      },
      "source": [
        "축은 종종 인덱스로 참조하지만, 항상 각 축의 의미를 추적해야 합니다. 축이 전역에서 로컬로 정렬되는 경우가 종종 있습니다. 배치 축이 먼저 오고 그 다음에 공간 차원과 각 위치의 특성이 마지막에 옵니다. 이러한 방식으로 특성 벡터는 연속적인 메모리 영역입니다.\n",
        "\n",
        "<table>\n",
        "<tr>\n",
        "<th>일반적인 축 순서</th>\n",
        "</tr>\n",
        "<tr>\n",
        "    <td> <img alt=\"Keep track of what each axis is. A 4-axis tensor might be: Batch, Width, Height, Freatures\" src=\"images/tensor/shape2.png\">\n",
        "</td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FlPoVvJS75Bb"
      },
      "source": [
        "## 인덱싱"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "apOkCKqCZIZu"
      },
      "source": [
        "### 단일 축 인덱싱\n",
        "\n",
        "TensorFlow는 [파이썬의 목록 또는 문자열 인덱싱](https://docs.python.org/3/tutorial/introduction.html#strings)과 마찬가지로 표준 파이썬 인덱싱 규칙과 numpy 인덱싱의 기본 규칙을 따릅니다.\n",
        "\n",
        "- 인덱스는 `0`에서 시작합니다.\n",
        "- 음수 인덱스는 끝에서부터 거꾸로 계산합니다.\n",
        "- 콜론, `:`은 슬라이스 `start:stop:step`에 사용됩니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SQ-CrJxLXTIM"
      },
      "outputs": [],
      "source": [
        "rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])\n",
        "print(rank_1_tensor.numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mQYYL56PXSak"
      },
      "source": [
        "스칼라를 사용하여 인덱싱하면 차원이 제거됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "n6tqHciOWMt5"
      },
      "outputs": [],
      "source": [
        "print(\"First:\", rank_1_tensor[0].numpy())\n",
        "print(\"Second:\", rank_1_tensor[1].numpy())\n",
        "print(\"Last:\", rank_1_tensor[-1].numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qJLHU_a2XwpG"
      },
      "source": [
        "`:` 조각으로 인덱싱하면 차원이 유지됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "giVPPcfQX-cu"
      },
      "outputs": [],
      "source": [
        "print(\"Everything:\", rank_1_tensor[:].numpy())\n",
        "print(\"Before 4:\", rank_1_tensor[:4].numpy())\n",
        "print(\"From 4 to the end:\", rank_1_tensor[4:].numpy())\n",
        "print(\"From 2, before 7:\", rank_1_tensor[2:7].numpy())\n",
        "print(\"Every other item:\", rank_1_tensor[::2].numpy())\n",
        "print(\"Reversed:\", rank_1_tensor[::-1].numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "elDSxXi7X-Bh"
      },
      "source": [
        "### 다축 인덱싱"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Cgk0uRUYZiai"
      },
      "source": [
        "더 높은 순위의 텐서는 여러 인덱스를 전달하여 인덱싱됩니다.\n",
        "\n",
        "단일 축의 경우에서와 정확히 같은 단일 축 규칙이 각 축에 독립적으로 적용됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Tc5X_WlsZXmd"
      },
      "outputs": [],
      "source": [
        "print(rank_2_tensor.numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "w07U9vq5ipQk"
      },
      "source": [
        "각 인덱스에 정수를 전달하면 결과는 스칼라입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PvILXc1PjqTM"
      },
      "outputs": [],
      "source": [
        "# Pull out a single value from a 2-rank tensor\n",
        "print(rank_2_tensor[1, 1].numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3RLCzAOHjfEH"
      },
      "source": [
        "정수와 슬라이스를 조합하여 인덱싱할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YTqNqsfJkJP_"
      },
      "outputs": [],
      "source": [
        "# Get row and column tensors\n",
        "print(\"Second row:\", rank_2_tensor[1, :].numpy())\n",
        "print(\"Second column:\", rank_2_tensor[:, 1].numpy())\n",
        "print(\"Last row:\", rank_2_tensor[-1, :].numpy())\n",
        "print(\"First item in last column:\", rank_2_tensor[0, -1].numpy())\n",
        "print(\"Skip the first row:\")\n",
        "print(rank_2_tensor[1:, :].numpy(), \"\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "P45TwSUVSK6G"
      },
      "source": [
        "다음은 3축 텐서의 예입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GuLoMoCVSLxK"
      },
      "outputs": [],
      "source": [
        "print(rank_3_tensor[:, :, 4])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9NgmHq27TJOE"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "<th colspan=\"2\">배치에서 각 예의 모든 위치에서 마지막 특성 선택하기</th>\n",
        "</tr>\n",
        "<tr>\n",
        "    <td><img alt=\"A 3x2x5 tensor with all the values at the index-4 of the last axis selected.\" src=\"images/tensor/index1.png\"></td>\n",
        "      <td><img alt=\"The selected values packed into a 2-axis tensor.\" src=\"images/tensor/index2.png\"></td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fpr7R0t4SVb0"
      },
      "source": [
        "## 형상 조작하기\n",
        "\n",
        "텐서의 형상을 바꾸는 것은 매우 유용합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EMeTtga5Wq8j"
      },
      "outputs": [],
      "source": [
        "# Shape returns a `TensorShape` object that shows the size on each dimension\n",
        "var_x = tf.Variable(tf.constant([[1], [2], [3]]))\n",
        "print(var_x.shape)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "38jc2RXziT3W"
      },
      "outputs": [],
      "source": [
        "# You can convert this object into a Python list, too\n",
        "print(var_x.shape.as_list())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "J_xRlHZMKYnF"
      },
      "source": [
        "텐서를 새로운 형상으로 바꿀 수 있습니다. 기본 데이터를 복제할 필요가 없으므로 재구성이 빠르고 저렴합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pa9JCgMLWy87"
      },
      "outputs": [],
      "source": [
        "# We can reshape a tensor to a new shape.\n",
        "# Note that we're passing in a list\n",
        "reshaped = tf.reshape(var_x, [1, 3])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Mcq7iXOkW3LK"
      },
      "outputs": [],
      "source": [
        "print(var_x.shape)\n",
        "print(reshaped.shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gIB2tOkoVr6E"
      },
      "source": [
        "데이터의 레이아웃은 메모리에서 유지되고 요청된 형상이 같은 데이터를 가리키는 새 텐서가 작성됩니다. TensorFlow는 C 스타일 \"행 중심\" 메모리 순서를 사용합니다. 여기에서 가장 오른쪽에 있는 인덱스를 증가시키면 메모리의 단일 단계에 해당합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7kMfM0RpUgI8"
      },
      "outputs": [],
      "source": [
        "print(rank_3_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TcDtfQkJWzIx"
      },
      "source": [
        "텐서를 평평하게 하면 어떤 순서로 메모리에 배치되어 있는지 확인할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "COnHEPuaWDQp"
      },
      "outputs": [],
      "source": [
        "# A `-1` passed in the `shape` argument says \"Whatever fits\".\n",
        "print(tf.reshape(rank_3_tensor, [-1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jJZRira2W--c"
      },
      "source": [
        "일반적으로, `tf.reshape`의 합리적인 용도는 인접한 축을 결합하거나 분할하는 것(또는 `1`을 추가/제거)입니다.\n",
        "\n",
        "이 3x2x5 텐서의 경우, 슬라이스가 혼합되지 않으므로 (3x2)x5 또는 3x (2x5)로 재구성하는 것이 합리적입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zP2Iqc7zWu_J"
      },
      "outputs": [],
      "source": [
        "print(tf.reshape(rank_3_tensor, [3*2, 5]), \"\\n\")\n",
        "print(tf.reshape(rank_3_tensor, [3, -1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6ZsZRUhihlDB"
      },
      "source": [
        "<table>\n",
        "<th colspan=\"3\">몇 가지 좋은 재구성</th>\n",
        "<tr>\n",
        "  <td><img alt=\"A 3x2x5 tensor\" src=\"images/tensor/reshape-before.png\"></td>\n",
        "  <td><img alt=\"The same data reshaped to (3x2)x5\" src=\"images/tensor/reshape-good1.png\"></td>\n",
        "  <td><img alt=\"The same data reshaped to 3x(2x5)\" src=\"images/tensor/reshape-good2.png\"></td>\n",
        "</tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nOcRxDC3jNIU"
      },
      "source": [
        "형상을 변경하면 같은 총 요소 수를 가진 새로운 형상에 대해 \"작동\"하지만, 축의 순서를 고려하지 않으면 별로 쓸모가 없습니다.\n",
        "\n",
        "`tf.reshape`에서 축 교환이 작동하지 않으면, `tf.transpose`를 수행해야 합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "I9qDL_8u7cBH"
      },
      "outputs": [],
      "source": [
        "# Bad examples: don't do this\n",
        "\n",
        "# You can't reorder axes with reshape.\n",
        "print(tf.reshape(rank_3_tensor, [2, 3, 5]), \"\\n\") \n",
        "\n",
        "# This is a mess\n",
        "print(tf.reshape(rank_3_tensor, [5, 6]), \"\\n\")\n",
        "\n",
        "# This doesn't work at all\n",
        "try:\n",
        "  tf.reshape(rank_3_tensor, [7, -1])\n",
        "except Exception as e:\n",
        "  print(f\"{type(e).__name__}: {e}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qTM9-5eh68oo"
      },
      "source": [
        "<table>\n",
        "<th colspan=\"3\">몇 가지 잘못된 재구성</th>\n",
        "<tr>\n",
        "  <td><img alt=\"You can't reorder axes, use tf.transpose for that\" src=\"images/tensor/reshape-bad.png\"></td>\n",
        "  <td><img alt=\"Anything that mixes the slices of data together is probably wrong.\" src=\"images/tensor/reshape-bad4.png\"></td>\n",
        "  <td><img alt=\"The new shape must fit exactly.\" src=\"images/tensor/reshape-bad2.png\"></td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N9r90BvHCbTt"
      },
      "source": [
        "완전히 지정되지 않은 형상에서 실행할 수 있습니다. 형상에 `None`(차원의 길이를 알 수 없음)이 포함되거나 형상이`None`(텐서의 순위를 알 수 없음)입니다.\n",
        "\n",
        "[tf.RaggedTensor](#ragged_tensors)를 제외하고, TensorFlow의 상징적인 그래프 빌딩 API의 컨텍스트에서만 발생합니다.\n",
        "\n",
        "- [tf.function](function.ipynb)\n",
        "- [keras 함수형 API](keras/functional.ipynb)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fDmFtFM7k0R2"
      },
      "source": [
        "## `DTypes`에 대한 추가 정보\n",
        "\n",
        "`tf.Tensor`의 데이터 유형을 검사하려면, `Tensor.dtype` 속성을 사용합니다.\n",
        "\n",
        "Python 객체에서 `tf.Tensor`를 만들 때 선택적으로 데이터 유형을 지정할 수 있습니다.\n",
        "\n",
        "그렇지 않으면, TensorFlow는 데이터를 나타낼 수 있는 데이터 유형을 선택합니다. TensorFlow는 Python 정수를 `tf.int32`로, Python 부동 소수점 숫자를 `tf.float32`로 변환합니다. 그렇지 않으면, TensorFlow는 NumPy가 배열로 변환할 때 사용하는 것과 같은 규칙을 사용합니다.\n",
        "\n",
        "유형별로 캐스팅할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5mSTDWbelUvu"
      },
      "outputs": [],
      "source": [
        "the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64)\n",
        "the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16)\n",
        "# Now, let's cast to an uint8 and lose the decimal precision\n",
        "the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)\n",
        "print(the_u8_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "s1yBlJsVlFSu"
      },
      "source": [
        "## 브로드캐스팅\n",
        "\n",
        "브로드캐스팅은 [NumPy의 해당 특성](https://numpy.org/doc/stable/user/basics.html)에서 빌린 개념입니다. 요컨대, 특정 조건에서 작은 텐서는 결합된 연산을 실행할 때 더 큰 텐서에 맞게 자동으로 \"확장(streched)\"됩니다.\n",
        "\n",
        "가장 간단하고 가장 일반적인 경우는 스칼라에 텐서를 곱하거나 추가하려고 할 때입니다. 이 경우, 스칼라는 다른 인수와 같은 형상으로 브로드캐스트됩니다. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "P8sypqmagHQN"
      },
      "outputs": [],
      "source": [
        "x = tf.constant([1, 2, 3])\n",
        "\n",
        "y = tf.constant(2)\n",
        "z = tf.constant([2, 2, 2])\n",
        "# All of these are the same computation\n",
        "print(tf.multiply(x, 2))\n",
        "print(x * y)\n",
        "print(x * z)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o0SBoR6voWcb"
      },
      "source": [
        "마찬가지로, 크기가 1인 차원은 다른 인수와 일치하도록 확장될 수 있습니다. 두 인수 모두 같은 계산으로 확장될 수 있습니다.\n",
        "\n",
        "이 경우, 3x1 행렬에 요소별로 1x4 행렬을 곱하여 3x4 행렬을 만듭니다. 선행 1이 선택 사항인 점에 유의하세요. y의 형상은 `[4]`입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6sGmkPg3XANr"
      },
      "outputs": [],
      "source": [
        "# These are the same computations\n",
        "x = tf.reshape(x,[3,1])\n",
        "y = tf.range(1, 5)\n",
        "print(x, \"\\n\")\n",
        "print(y, \"\\n\")\n",
        "print(tf.multiply(x, y))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "t_7sh-EUYLrE"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>추가 시 브로드캐스팅: <code>[1, 4]</code>와 <code>[3, 1]</code>의 곱하기는 <code>[3,4]</code>입니다.</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td><img alt=\"Adding a 3x1 matrix to a 4x1 matrix results in a 3x4 matrix\" src=\"images/tensor/broadcasting.png\"></td>\n",
        "</tr>\n",
        "</table>\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9V3KgSJcKDRz"
      },
      "source": [
        "브로드캐스팅이 없는 같은 연산이 여기 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "elrF6v63igY8"
      },
      "outputs": [],
      "source": [
        "x_stretch = tf.constant([[1, 1, 1, 1],\n",
        "                         [2, 2, 2, 2],\n",
        "                         [3, 3, 3, 3]])\n",
        "\n",
        "y_stretch = tf.constant([[1, 2, 3, 4],\n",
        "                         [1, 2, 3, 4],\n",
        "                         [1, 2, 3, 4]])\n",
        "\n",
        "print(x_stretch * y_stretch)  # Again, operator overloading"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "14KobqYu85gi"
      },
      "source": [
        "대부분의 경우 브로드캐스팅은 브로드캐스트 연산으로 메모리에서 확장된 텐서를 구체화하지 않으므로 시간과 공간 효율적입니다.\n",
        "\n",
        "`tf.broadcast_to`를 사용하여 브로드캐스팅이 어떤 모습인지 알 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GW2Q59_r8hZ6"
      },
      "outputs": [],
      "source": [
        "print(tf.broadcast_to(tf.constant([1, 2, 3]), [3, 3]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z2bAMMQY-jpP"
      },
      "source": [
        "예를 들어, `broadcast_to`는 수학적인 op와 달리 메모리를 절약하기 위해 특별한 연산을 수행하지 않습니다. 여기에서 텐서를 구체화합니다.\n",
        "\n",
        "훨씬 더 복잡해질 수 있습니다. Jake VanderPlas의 저서 *Python Data Science Handbook*의 [해당 섹션](https://jakevdp.github.io/PythonDataScienceHandbook/02.05-computation-on-arrays-broadcasting.html)에서는 더 많은 브로드캐스팅 트릭을 보여줍니다(NumPy에서)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o4Rpz0xAsKSI"
      },
      "source": [
        "## tf.convert_to_tensor\n",
        "\n",
        "`tf.matmul` 및 `tf.reshape`와 같은 대부분의 ops는 클래스 `tf.Tensor`의 인수를 사용합니다. 그러나 위의 경우, 텐서 형상의 Python 객체를 자주 전달합니다.\n",
        "\n",
        "전부는 아니지만 대부분의 ops는 텐서가 아닌 인수에 대해 `convert_to_tensor`를 호출합니다. 변환 레지스트리가 있어 NumPy의 `ndarray`, `TensorShape` , Python 목록 및 `tf.Variable`과 같은 대부분의 객체 클래스는 모두 자동으로 변환됩니다.\n",
        "\n",
        "자세한 내용은 `tf.register_tensor_conversion_function`을 참조하세요. 자신만의 유형이 있으면 자동으로 텐서로 변환할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "05bBVBVYV0y6"
      },
      "source": [
        "## 비정형 텐서\n",
        "\n",
        "어떤 축을 따라 다양한 수의 요소를 가진 텐서를 \"비정형(ragged)\"이라고 합니다. 비정형 데이터에는 `tf.ragged.RaggedTensor`를 사용합니다.\n",
        "\n",
        "예를 들어, 비정형 텐서는 정규 텐서로 표현할 수 없습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VPc3jGoeJqB7"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>`tf.RaggedTensor`, 형상: <code>[4, None]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td><img alt=\"A 2-axis ragged tensor, each row can have a different length.\" src=\"images/tensor/ragged.png\"></td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VsbTjoFfNVBF"
      },
      "outputs": [],
      "source": [
        "ragged_list = [\n",
        "    [0, 1, 2, 3],\n",
        "    [4, 5],\n",
        "    [6, 7, 8],\n",
        "    [9]]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "p4xKTo57tutG"
      },
      "outputs": [],
      "source": [
        "try:\n",
        "  tensor = tf.constant(ragged_list)\n",
        "except Exception as e:\n",
        "  print(f\"{type(e).__name__}: {e}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0cm9KuEeMLGI"
      },
      "source": [
        "대신 `tf.ragged.constant`를 사용하여 `tf.RaggedTensor`를 작성합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "XhF3QV3jiqTj"
      },
      "outputs": [],
      "source": [
        "ragged_tensor = tf.ragged.constant(ragged_list)\n",
        "print(ragged_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sFgHduHVNoIE"
      },
      "source": [
        "`tf.RaggedTensor`의 형상에는 알 수 없는 차원이 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Eo_3wJUWNgqB"
      },
      "outputs": [],
      "source": [
        "print(ragged_tensor.shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V9njclVkkN7G"
      },
      "source": [
        "## 문자열 텐서\n",
        "\n",
        "`tf.string`은 `dtype`이며, 텐서에서 문자열(가변 길이의 바이트 배열)과 같은 데이터를 나타낼 수 있습니다.\n",
        "\n",
        "문자열은 원자성이므로 Python 문자열과 같은 방식으로 인덱싱할 수 없습니다. 문자열의 길이는 텐서의 차원 중의 하나가 아닙니다. 문자열을 조작하는 함수에 대해서는 `tf.strings`를 참조하세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5P_8spEGQ0wp"
      },
      "source": [
        "다음은 스칼라 문자열 텐서입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sBosmM8MkIh4"
      },
      "outputs": [],
      "source": [
        "# Tensors can be strings, too here is a scalar string.\n",
        "scalar_string_tensor = tf.constant(\"Gray wolf\")\n",
        "print(scalar_string_tensor)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CMFBSl1FQ3vE"
      },
      "source": [
        "문자열의 벡터는 다음과 같습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IO-c3Tq3RC1L"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>문자열의 벡터, 형상: <code>[3,]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td><img alt=\"The string length is not one of the tensor's axes.\" src=\"images/tensor/strings.png\"></td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "41Dv2kL9QrtO"
      },
      "outputs": [],
      "source": [
        "# If we have two string tensors of different lengths, this is OK.\n",
        "tensor_of_strings = tf.constant([\"Gray wolf\",\n",
        "                                 \"Quick brown fox\",\n",
        "                                 \"Lazy dog\"])\n",
        "# Note that the shape is (2,), indicating that it is 2 x unknown.\n",
        "print(tensor_of_strings)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "76gQ9qrgSMzS"
      },
      "source": [
        "위의 출력에서 `b` 접두사는 `tf.string` dtype이 유니코드 문자열이 아니라 바이트 문자열임을 나타냅니다. TensorFlow에서 유니코드 텍스트를 처리하는 자세한 내용은 [유니코드 튜토리얼](https://www.tensorflow.org/tutorials/load_data/unicode)을 참조하세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ClSBPK-lZBQp"
      },
      "source": [
        "유니코드 문자를 전달하면 UTF-8로 인코딩됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GTgL53jxSMd9"
      },
      "outputs": [],
      "source": [
        "tf.constant(\"🥳👍\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ir9cY42MMAei"
      },
      "source": [
        "문자열이 있는 일부 기본 함수는 `tf.strings`을 포함하여 `tf.strings.split`에서 찾을 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8k2K0VTFyj8e"
      },
      "outputs": [],
      "source": [
        "# We can use split to split a string into a set of tensors\n",
        "print(tf.strings.split(scalar_string_tensor, sep=\" \"))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zgGAn1dfR-04"
      },
      "outputs": [],
      "source": [
        "# ...but it turns into a `RaggedTensor` if we split up a tensor of strings,\n",
        "# as each string might be split into a different number of parts.\n",
        "print(tf.strings.split(tensor_of_strings))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HsAn1kPeO84m"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>세 개의 분할된 문자열, 형상: <code>[3, None]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td><img alt=\"Splitting multiple strings returns a tf.RaggedTensor\" src=\"images/tensor/string-split.png\"></td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "st9OxrUxWSKY"
      },
      "source": [
        "`tf.string.to_number`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3nRtx3X9WRfN"
      },
      "outputs": [],
      "source": [
        "text = tf.constant(\"1 10 100\")\n",
        "print(tf.strings.to_number(tf.strings.split(text, \" \")))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "r2EZtBbJBns4"
      },
      "source": [
        "`tf.cast`를 사용하여 문자열 텐서를 숫자로 변환할 수는 없지만, 바이트로 변환한 다음 숫자로 변환할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fo8BjmH7gyTj"
      },
      "outputs": [],
      "source": [
        "byte_strings = tf.strings.bytes_split(tf.constant(\"Duck\"))\n",
        "byte_ints = tf.io.decode_raw(tf.constant(\"Duck\"), tf.uint8)\n",
        "print(\"Byte strings:\", byte_strings)\n",
        "print(\"Bytes:\", byte_ints)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uSQnZ7d1jCSQ"
      },
      "outputs": [],
      "source": [
        "# Or split it up as unicode and then decode it\n",
        "unicode_bytes = tf.constant(\"アヒル 🦆\")\n",
        "unicode_char_bytes = tf.strings.unicode_split(unicode_bytes, \"UTF-8\")\n",
        "unicode_values = tf.strings.unicode_decode(unicode_bytes, \"UTF-8\")\n",
        "\n",
        "print(\"\\nUnicode bytes:\", unicode_bytes)\n",
        "print(\"\\nUnicode chars:\", unicode_char_bytes)\n",
        "print(\"\\nUnicode values:\", unicode_values)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fE7nKJ2YW3aY"
      },
      "source": [
        "`tf.string` dtype은 TensorFlow의 모든 원시 바이트 데이터에 사용됩니다. `tf.io` 모듈에는 이미지 디코딩 및 csv 구문 분석을 포함하여 데이터를 바이트로 변환하거나 바이트에서 변환하는 함수가 포함되어 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ua8BnAzxkRKV"
      },
      "source": [
        "## 희소 텐서\n",
        "\n",
        "때로는 매우 넓은 임베드 공간과 같이 데이터가 희소합니다. TensorFlow는 `tf.sparse.SparseTensor` 및 관련 연산을 지원하여 희소 데이터를 효율적으로 저장합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mS5zgqgUTPRb"
      },
      "source": [
        "<table>\n",
        "<tr>\n",
        "  <th>`tf.SparseTensor`, 형상: <code>[3, 4]</code>\n",
        "</th>\n",
        "</tr>\n",
        "<tr>\n",
        "  <td><img alt=\"An 3x4 grid, with values in only two of the cells.\" src=\"images/tensor/sparse.png\"></td>\n",
        "</tr>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "B9nbO1E2kSUN"
      },
      "outputs": [],
      "source": [
        "# Sparse tensors store values by index in a memory-efficient manner\n",
        "sparse_tensor = tf.sparse.SparseTensor(indices=[[0, 0], [1, 2]],\n",
        "                                       values=[1, 2],\n",
        "                                       dense_shape=[3, 4])\n",
        "print(sparse_tensor, \"\\n\")\n",
        "\n",
        "# We can convert sparse tensors to dense\n",
        "print(tf.sparse.to_dense(sparse_tensor))"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "Tce3stUlHN0L"
      ],
      "name": "tensor.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
